<?php

abstract class ContentPage implements IHTMLNode {
	protected $_cacheParams = array();
	protected $_html = null;
	protected $_dom = null;

	private $_uuid;
	private $_mtime;
	private $_params;

	public abstract function Render();
	public abstract function LastModified();
	public abstract function IsCachable();

	public final function Process() {
		if ($this->IsCachable() !== true) {
			return $this->Render();
		} else {
			if ($content = $this->GetCached()) {
				return $content;
			} else {
				$content = $this->Render();
				$this->Cache($content);
				return $content;
			}
		}
	}

	public function GetUUID() {
		return get_class($this);
	}

	public function GetCacheParameters() {
		return $this->_cacheParams;
	}

	public function SetCacheParameters(array $values) {
		$this->_cacheParams = $values;
	}

	public function GetCached() {
		$this->_uuid = md5($this->GetUUID());
		$this->_mtime = $this->GetLastModified()->Value;
		$this->_params = !is_null($this->_cacheParams) ? serialize($this->_cacheParams) : null;

//var_dump($this->_mtime);exit;

		$cached = DB::Table('Cache')
			->Columns('Content')
			->Where('UUID', EQ, $this->_uuid)
			->Where('Params', EQ, $this->_params)
			->Where('LastModified', GTE, $this->_mtime)
			->OrderBy('LastModified', DESC)
			->Single();

		return DB::IfNull($cached->Content, false);
	}

	public function Cache($content) {
		return DB::Table('Cache')->NewObject(array(
			'UUID' => $this->_uuid,
			'Params' => $this->_params,
			'LastModified' => $this->_mtime,
			'Content' => $content
		))->Save();
	}

	private function GetLastModified() {
		$lm = $this->LastModified();
		if (is_array($lm)) {
			$times = $lm;
			$lm = 0;
			foreach ($times as $time) {
				if (is_object($time) && $time instanceof DBDateTime) {
					$time = $time->Value;
				} else if (is_string($time)) {
					$time = strtotime($time);
				}

				if (is_integer($time) || is_float($time)) {
					if ($time > $lm) {
						$lm = $time;
					}
				}
			}
		}
		return $lm;
	}

	public function appendChild(&$childNode) {
		return $this->renderDOM()->appendChild(&$childNode);
	}

	public function removeChild(&$childNode) {
		return $this->renderDOM()->removeChild(&$childNode);
	}

	public function getElementById($id) {
		return $this->renderDOM()->getElementById($id);
	}

	public function getElementsByTagName($tagName) {
		return $this->renderDOM()->getElementsByTagName($tagName);
	}

	public function renderDOM() {
		if (is_null($this->_dom)) {
			$this->_dom = HTML::Parse($this->RenderHTML());
		}
		return $this->_dom;
	}

	public function renderHTML() {
		if (is_null($this->_html)) {
			$this->_html = $this->Process();
		}
		return $this->_html;
	}
}
